#ifndef XGE_UNITTEST_XPRIORITY_QUEUE_H_
#define XGE_UNITTEST_XPRIORITY_QUEUE_H_
#include "xge_common_config.h"
#include "xpriority_task.h"
#include "xworker_priority_queue.h"
#include "xunit_test.h"
#include "xthread.h"
#include "xthread_delegate.h"
#include "xthread_manager.h"
#include "xassert.h"
#include "xsync.h"
#include "xtimer.h"
#include "xtask_memory_helper.h"
#include <stdio.h>


using xge::PriorityTask;
using xge::xge_internal::WorkerQueue;
using xge::xge_internal::WorkerPriorityQueue;
using xge::xge_internal::ThreadHandler;
using xge::xge_internal::ThreadHandlerPtr;
using xge::xge_internal::ThreadDelegate;
using xge::xge_internal::ThreadDelegatePtr;
using xge::xge_internal::ThreadManager;
using xge::String;
using xge::xge_internal::LoopTicking;
using xge::xge_internal::Timer;
using xge::xge_internal::TaskPtr;
using xge::xge_internal::TaskMemoryHelper;

namespace {

  // A stub priority task
  class MyPriorityTask : public PriorityTask{
  public:
    MyPriorityTask( PriorityTask::priority_t pri , const String& name ): PriorityTask(pri,REMOTE_BINDING,name) {}
    // Execute something ....
    virtual void Execute() {
      for( size_t i = 0 ; i < 10 ; ++i ) {
        printf("XXXXXXX:%d\n",priority());
      }
    }
  };
  // A thread will execute the XWorkerQueue

  class MyWorkerQueueStub : public ThreadDelegate {
  public:
    // thread main 
    virtual void ThreadMain() {
      queue_.Loop();
    }
    // post quit
    void PostQuit() {
      queue_.PostQuitSoon();
    }
    void PostQuitWhenEmpty() {
      queue_.PostQuitWhenEmpty();
    }
    void WaitWhenEmpty(){
      queue_.WaitWhenEmpty();
    }

    bool WaitWhenEmpty( int ms ){
      return queue_.WaitWhenEmpty(ms);
    }


    MyWorkerQueueStub() : delegate_ptr_(this){
      // Initialize the thread stuff
      int ec_code ;
      handler_ = ThreadManager::CreateXThread(
        &ec_code,
        delegate_ptr_,
        _xT("MyWorkerPriorityThread"),
        "priority_thread"
        );
      XASSERT( !handler_.Null() );

    }

    void WaitWhenRelease() {
      queue_.WaitWhenRelease();
    }

    void WaitWhenRelease( int ms ) {
      queue_.WaitWhenRelease(ms);
    }

    void Push( const TaskPtr & ptr ) {
      queue_.PushTask(ptr);
    }

    void PushBatch( WorkerQueue::TaskPtrList* task_container ) {
      queue_.PushTask(task_container);
    }

    bool TryPush( const TaskPtr& ptr ) {
      queue_.TryPushTask(ptr);
    }

    size_t size() const {
      return queue_.size();
    }

  public:
    WorkerPriorityQueue queue_;
    ThreadHandlerPtr handler_;
    ThreadDelegatePtr delegate_ptr_;
  };


}

// UNIT_TEST(XPRIORITY_QUEUE,Case2) {
// 
//   // You should always use new to work with smart_ptr 
//   MyWorkerQueueStub* stub = new MyWorkerQueueStub();
//   // Spawn as much work as possible
//   XTimer timer;
//   timer.BeginTimerCounting();
//   // loop times 
//   size_t iLoopTimes = 0;
//   while(1) {
//     // do not do any thing here
//     XLoopSync::UpdateLoopSync( timer.TimeDiff() );
//     for( size_t i = 0 ; i < 10 ; ++i ) {
//       stub->Push( XTaskPtr( new MyPriorityTask(i,_xT("hehe"))) );
//     }
//     ++iLoopTimes;
//     if( iLoopTimes >= 10 ) {
//       // Pay attention here !
//       for( size_t j = 0 ; j < 100 ; ++j ) 
//         stub->PostQuitWhenEmpty();
//       while( !(stub->WaitWhenEmpty(1)) ) {
//         printf("work:%d\n",(int)(stub->size()));
//       }
//       stub->handler_->Join();
//       break;
//     }
//   }
//   // XASSERT( ThreadManager::GetAllocatedThreadSize() == 0 );
//   printf("TestOver2\n");
//   delete stub;
// }

// This test case is testing the wake up mechanism is useful or not

// wait when sleep

void WaitWhenSleep( WorkerQueue* queue ) {
  while( !(queue->sleep()) ) {
    ThreadManager::SwithToAnotherThread();
  }
}

UNIT_TEST(XPRIORITY_QUEUE,Case3) {
  MyWorkerQueueStub* stub = new MyWorkerQueueStub();
  Timer timer;
  size_t iCount=0;
  while(1) {
    LoopTicking::UpdateLoopSync( timer.TimeDiff() );
    // when reaching here we will find that the thread is sleep now 
    stub->Push( TaskPtr( new MyPriorityTask(1,_xT("hehe"))) );
    stub->WaitWhenEmpty();
    WaitWhenSleep(&(stub->queue_));
    ++iCount;
    if( iCount== 100 ) {
      stub->PostQuitWhenEmpty();
      stub->WaitWhenRelease();
      stub->handler_->Join();
      break;
    }
  }
  delete stub;
  printf("Test Case3 Over!");
}

#endif// XGE_UNITTEST_XPRIORITY_QUEUE_H_